/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package airAgent.group5;

//import airAgent.group5.ontology.ontology.AirAgentOntology;
import airAgent.group5.ontology.ontology.*;
import jade.content.Concept;
import jade.content.ContentElement;
import jade.content.lang.Codec;
import jade.content.lang.sl.SLCodec;
import jade.content.onto.Ontology;
import jade.core.AID;
import jade.core.Agent;
import jade.core.behaviours.CyclicBehaviour;
import jade.domain.DFService;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.content.lang.Codec;
import jade.content.lang.Codec.CodecException;
import jade.content.lang.sl.SLCodec;
import jade.content.onto.Ontology;
import jade.content.onto.OntologyException;
import jade.content.onto.basic.Action;
import jade.core.behaviours.SimpleBehaviour;
import jade.wrapper.AgentController;
import jade.wrapper.StaleProxyException;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author hector
 */
public class ClientGenerator extends Agent {

    private AID timerRef;
    private boolean hasTimer = false;
    private Codec codec = new SLCodec();
    private Ontology ontology = AirAgentOntology.getInstance();
    private int clientsPerDay = -1;
    private int dailyPassengersVariance = -1;
    //private String configFileDir = "/home/alex/workspace/absd-group5/bin/airAgent/group5";
    private ArrayList<AgentController> clients = null;
    private int lastClientIndex = 1;
    private int today = 0;
    private int Min;
    private int Max;

    private class SubscribeTimerBehaviour extends CyclicBehaviour {

        private boolean end = false;
        private int tries = 0;

        public void action() {

            // Creates the description for the type of agent to be searched
            DFAgentDescription dfd = new DFAgentDescription();
            ServiceDescription sd = new ServiceDescription();
            sd.setType(AirAgentOntology.TIMER);		// SHOULD USE THE ONTOLOGY  (ontoBank)
            dfd.addServices(sd);
            if (hasTimer()) {
                removeBehaviour(this);
            } else {
                try {
                    tries++;
                    // System.out.println(tries + " tries to subscribe timer");
                    // It finds agents of the required type
                    DFAgentDescription[] res = new DFAgentDescription[1];
                    res = DFService.search(myAgent, dfd);
                    if (res.length > 0) {
                        timerRef = (AID) res[0].getName();
                        ACLMessage msg = new ACLMessage(ACLMessage.SUBSCRIBE);
                        msg.addReceiver(timerRef);
                        msg.setLanguage(codec.getName());
                        msg.setOntology(ontology.getName());
                        msg.setProtocol(AirAgentOntology.SUBSCRIBETIMER);
                        SubscribeTimer subscribeTimer = new SubscribeTimer();
                        // As it is an action and the encoding language the SL, it must be wrapped
                        // into an Action
                        Action agAction = new Action(timerRef, subscribeTimer);
                        try {
                            // The ContentManager transforms the java objects into strings
                            getContentManager().fillContent(msg, agAction);
                            send(msg);
                            end = true;
                            //    System.out.println(getLocalName() + ": wants to subscribe to timer");
                        } catch (CodecException ce) {
                            ce.printStackTrace();
                        } catch (OntologyException oe) {
                            oe.printStackTrace();
                        }
                        hasTimer = true;
                        addBehaviour(new ResponseSubscribeTimerBehaviour());
                    }
                } catch (Exception e) {
                }
            }
        }
    }

    private class ResponseSubscribeTimerBehaviour extends SimpleBehaviour {

        @Override
        public void action() {
            ACLMessage msg = receive(MessageTemplate.MatchProtocol(AirAgentOntology.SUBSCRIBETIMER));
            if (msg != null) {
                if (msg.getPerformative() == ACLMessage.AGREE) {
                    hasTimer = true;
           //         System.out.println(getLocalName() + ": Subscribed to Timer");
                }
            } else {
                block();
            }

        }

        @Override
        public boolean done() {
            return hasTimer();
        }
    }

    private class WaitToBehaviour extends SimpleBehaviour {

        private boolean end = false;

        public void action() {
            ACLMessage msg = receive(MessageTemplate.MatchProtocol(AirAgentOntology.STARTSIMULATION));

            if (msg != null) {
       //         System.out.println(getLocalName() + ": Starts...");
                end = true;
                addBehaviour(new InformDayBehaviour());
            } else {
                block();
            }
        }

        @Override
        public boolean done() {
            return end;
        }
    }

    private class EndSimlationBehaviour extends SimpleBehaviour {

        boolean end = false;

        public void action() {
            ACLMessage msg = receive(MessageTemplate.MatchProtocol(AirAgentOntology.ENDOFSIMULATION));

            if (msg != null) {
                //  System.out.println(getLocalName() + ": Ending...");
//                for (int i= 0; i < clients.size();i++)
//                {
//                    AgentController client = clients.get(i);
//                    try {
//                        client.kill();
//                    } catch (StaleProxyException ex) {
//                        System.out.println("Cannot kill client: c"+i);
//                    }
//                }
            } else {
                block();
            }
        }

        @Override
        public boolean done() {
            //for now just call takeDown, but should be remove all behaviour and inform monitor
            if (end == true) {
                takeDown();
            }
            return end;
        }
    }

    private class InformDayBehaviour extends CyclicBehaviour {

        int newClients = 0;

        public void action() {
            ACLMessage msg = receive(MessageTemplate.MatchProtocol(AirAgentOntology.INFORMDATE));

            if (msg != null) {
                if (msg.getPerformative() == ACLMessage.INFORM) {
                    try {
                        ContentElement ce = getContentManager().extractContent(msg);
                        if (ce instanceof Action) {
                            Action agAction = (Action) ce;
                            Concept conc = agAction.getAction();
                            if (conc instanceof InformDate) {
                                InformDate id = (InformDate) conc;

                                // NEW DAY
                                today = id.getDate();
                        		int ranNumber = Min + (int)(Math.random() * ((Max - Min) + 1));
                                newClients = ranNumber;
                                //newClients = (clientsPerDay - dailyPassengersVariance) + (int) (Math.random() * (((clientsPerDay + dailyPassengersVariance) - (clientsPerDay - dailyPassengersVariance)) + 1));
                                for (int i = 0; i < newClients; i++) {
                                    createClient();
                                }

                            }
                        }
                    } catch (CodecException e) {
                        e.printStackTrace();
                    } catch (OntologyException oe) {
                        oe.printStackTrace();
                    }
                }
            } else {
                block();
            }
        }
    }

    private boolean createClient() {
        boolean res = false;

        try {
            Object[] day = new Object[1];
            day[0] = ""+today;
            AgentController client = getContainerController().createNewAgent("c" + lastClientIndex, Client.class.getName(), day);
            clients.add(client);
            lastClientIndex++;
            client.start();
            res = true;
        } catch (StaleProxyException ex) {
            System.out.println(getLocalName() + ": Cannot create client agent");
        }
        return res;
    }

    private boolean readConfigFile() {


        try {
            File file = new File("settings.properties");
            Scanner scanner = new Scanner(file);
            while (scanner.hasNextLine()) {
                String configFileLine = scanner.nextLine();
                try {
                    String[] variableValue = configFileLine.split("=");
                    if (variableValue[0].equals("clientsPerDay")) {
                        setClientsPerDay(Integer.parseInt(variableValue[1]));
                    } else if (variableValue[0].equals("dailyPassengersVariance")) {
                        setdailyPassengersVariance(Integer.parseInt(variableValue[1]));
                    }
                } catch (Exception e) {
                    System.out.println(getLocalName() + ":Cannot parse line in config file: " + configFileLine);
                    e.printStackTrace();
                }

            }
            scanner.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return false;
        }
        if ((clientsPerDay != -1) && (dailyPassengersVariance != -1)) {
            return true;
        }
        return false;
    }

    private void setClientsPerDay(int count) {
        clientsPerDay = count;
    }

    private void setdailyPassengersVariance(int count) {
        dailyPassengersVariance = count;
    }

    protected void setup() {
        //System.out.println(getLocalName() + ": Created");
        System.out.println("client generator: enters into the system");
        getContentManager().registerLanguage(codec);
        getContentManager().registerOntology(ontology);
        readConfigFile();
        clients = new ArrayList<AgentController>();
        addBehaviour(new SubscribeTimerBehaviour());
        addBehaviour(new WaitToBehaviour());
        addBehaviour(new EndSimlationBehaviour());
        
		int cliPerDay = ConfigReader.getInstance().getClientsPerDay();
		int variance = ConfigReader.getInstance().getDailyPassengersVariance();
		Min = cliPerDay - variance;
		Max = cliPerDay + variance;        
    }

    public boolean hasTimer() {
        return hasTimer;
    }
}
